﻿using System.Net;
using System.Text;

using BodaNetCommunications.CIPComs.CipUtils;
using BodaNetCommunications.Cores;
using BodaNetCommunications.FinsComs;
using BodaNetCommunications.Utilities.Results;
using BodaNetCommunications.Utilities.Tools;

namespace BodaNetCommunications.CIPComs
{
    public class Cip : ICommDevice
    {
        #region Static Service Code

        /// <summary>
        /// CIP命令中的读取数据的服务
        /// </summary>
        public const byte CIP_READ_DATA = 0x4C;
        /// <summary>
        /// CIP命令中的写数据的服务
        /// </summary>
        public const int CIP_WRITE_DATA = 0x4D;
        /// <summary>
        /// CIP命令中的读并写的数据服务
        /// </summary>
        public const int CIP_READ_WRITE_DATA = 0x4E;
        /// <summary>
        /// CIP命令中的读片段的数据服务
        /// </summary>
        public const int CIP_READ_FRAGMENT = 0x52;
        /// <summary>
        /// CIP命令中的写片段的数据服务
        /// </summary>
        public const int CIP_WRITE_FRAGMENT = 0x53;
        /// <summary>
        /// CIP命令中的对数据读取服务
        /// </summary>
        public const int CIP_MULTIREAD_DATA = 0x1000;

        #endregion

        #region DataType Code

        /// <summary>
        /// bool型数据，一个字节长度
        /// </summary>
        public const ushort CIP_Type_Bool = 0xC1;

        /// <summary>
        /// byte型数据，一个字节长度
        /// </summary>
        public const ushort CIP_Type_Byte = 0xC2;

        /// <summary>
        /// 整型，两个字节长度
        /// </summary>
        public const ushort CIP_Type_Word = 0xC3;

        /// <summary>
        /// 长整型，四个字节长度
        /// </summary>
        public const ushort CIP_Type_DWord = 0xC4;

        /// <summary>
        /// 特长整型，8个字节
        /// </summary>
        public const ushort CIP_Type_LInt = 0xC5;

        /// <summary>
        /// 实数数据，四个字节长度
        /// </summary>
        public const ushort CIP_Type_Real = 0xCA;

        /// <summary>
        /// 实数数据，八个字节的长度
        /// </summary>
        public const ushort CIP_Type_Double = 0xCB;

        /// <summary>
        /// 结构体数据，不定长度
        /// </summary>
        public const ushort CIP_Type_Struct = 0xCC;

        /// <summary>
        /// 字符串数据内容
        /// </summary>
        public const ushort CIP_Type_String = 0xD0;

        /// <summary>
        /// 二进制数据内容
        /// </summary>
        public const ushort CIP_Type_BitArray = 0xD3;

        #endregion

        #region Public Properties

        /// <summary>
        /// The current session handle, which is determined by the PLC when communicating with the PLC handshake
        /// </summary>
        public uint SessionHandle { get; private set; }

        /// <summary>
        /// Gets or sets the slot number information for the current plc, which should be set before connections
        /// </summary>
        public byte Slot { get; set; } = 0;

        /// <summary>
        /// when read array type, this means the segment length. when data type is 8-byte data, it should set to be 50
        /// </summary>
        public int ArraySegment { get; set; } = 100;

        #endregion

        public ConnectionOptions Options { get; private set; }

        public bool IsConnected => _commUnit != null && _commUnit.IsConnected;

        private ICommUnit _commUnit;

        protected readonly IByteTransform _byteTransform;

        public Cip()
        {
            _byteTransform = new CipByteTransformBase();
        }
        public BodaResult Connect(ConnectionOptions connectionOptions)
        {
            BodaResult bodaResult = new BodaResult();
            Options = connectionOptions;

            if (string.IsNullOrEmpty(Options.Ip) || false == IPAddress.TryParse(Options.Ip, out _))
            {
                bodaResult.IsSuccess = false;
                bodaResult.Message = $"Ip[{Options.Ip}]为空或者格式不正确";
                return bodaResult;
            }

            if (Options.Port < 0 || Options.Port > 65535)
            {
                bodaResult.IsSuccess = false;
                bodaResult.Message = $"Port[{Options.Port}]不正确";
                return bodaResult;
            }

            if (IsConnected)
            {
                bodaResult.IsSuccess = true;
                bodaResult.Message = $"Cip【{Options.Ip}:{Options.Port}】的连接已经在线，不需要重复连接";
                return bodaResult;
            }

            _commUnit = new CommUnitCip(Options.Ip.Trim(), Options.Port);

            BodaResult<bool> result = _commUnit.Open(Options.ConnectTimeout);

            if (!result.IsSuccess)
            {
                bodaResult.IsSuccess = true;
                bodaResult.Message = bodaResult.Message;
                return bodaResult;
            }
            // 握手会话获取会话句柄
            bodaResult = HandShake();

            return bodaResult;

        }

        public void Disconnect()
        {
            if (_commUnit == null) return;

            ExtraOnDisconnect();
            _commUnit?.Close();
            _commUnit = null;
        }

        public BodaResult<byte> ReceiveMsg(int timeout = 2000, int bytesLen = 1024)
        {
            throw new NotImplementedException();
        }

        public BodaResult SendMsgc(byte[] bytes, int timeout = 1500)
        {
            throw new NotImplementedException();
        }

        /***************************************************************************
        // 注册会话ID　　
        private byte[] Registercmd = new byte[28]
        {
　　          //----------------------Header 24byte----------------------
　　          0x65,0x00,//命令 2byte
　　          0x04,0x00,//Header后面数据的长度 2byte
　　          0x00,0x00,0x00,0x00,//会话句柄 4byte
　　          0x00,0x00,0x00,0x00,//状态默认0 4byte
　　          0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//发送方描述默认0 8byte
　　          0x00,0x00,0x00,0x00,//选项默认0 4byte

              //---------------------CommandSpecificData 指令指定数据 4byte
　　          0x01,0x00,//协议版本 2byte
　　          0x00,0x00,//选项标记 2byte
        };
         */
        private BodaResult HandShake()
        {
            BodaResult bodaResult = new BodaResult();
            var bytes = RegisterSessionHandle();
            var resTx = _commUnit.SendAndReceive(bytes.ToList());
            if (!resTx.IsSuccess) return resTx;

            /***************************************************************************
            // 提取会话ID-注册请求的应答报文
            private byte[] RefRegistercmd = new byte[28] 
            {

　　            //----------------------Header 24byte----------------------
　　            0x65,0x00, // 命令 2byte
　　            0x04,0x00, // CommandSpecificData的长度 2byte
　　            0x6B,0x01,0x01,0x00, // 会话句柄 4byte 由PLC生成
　　            0x00,0x00,0x00,0x00, // 状态默认0 4byte
　　            0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 发送方描述默认0 8byte
　　            0x00,0x00,0x00,0x00, // 选项默认0 4byte

               //----------------------CommandSpecificData 指令指定数据 4byte
　　            0x01,0x00,//协议版本 2byte
　　            0x00,0x00,//选项标记 2byte
            };

            // 从应答报文提取的会话ID
            public byte[] SessionHandle=new byte[4]{0x6B,0x01,0x01,0x00};
             */
            // Check the returned status
            BodaResult? check = CheckResponse(resTx.Datas.ToArray());
            if (!check.IsSuccess) return check;

            //会话句柄 4byte 由PLC生成, 从第4个字节开始的4个字节
            // Extract session ID
            SessionHandle = _byteTransform.TransUInt32(resTx.Datas.ToArray(), 4);

            return check;
        }

        /// <summary>
        /// 检查返回值的结果
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        private BodaResult CheckResponse(byte[] response)
        {
            try
            {
                int status = _byteTransform.TransInt32(response, 8);
                if (status == 0) return BodaResult.CreateSuccessResult();

                string msg = string.Empty;
                switch (status)
                {
                    case 0x01: msg = StringResources.Language.AllenBradleySessionStatus01; break;
                    case 0x02: msg = StringResources.Language.AllenBradleySessionStatus02; break;
                    case 0x03: msg = StringResources.Language.AllenBradleySessionStatus03; break;
                    case 0x64: msg = StringResources.Language.AllenBradleySessionStatus64; break;
                    case 0x65: msg = StringResources.Language.AllenBradleySessionStatus65; break;
                    case 0x69: msg = StringResources.Language.AllenBradleySessionStatus69; break;
                    default: msg = StringResources.Language.UnknownError; break;
                }

                return new BodaResult(status, msg);
            }
            catch (Exception ex)
            {
                return new BodaResult(ex.Message);
            }
        }

        /// <summary>
        /// 向PLC注册会话ID的报文 ->
        /// Register a message with the PLC for the session ID
        /// </summary>
        /// <returns>报文信息 -> Message information </returns>
        public byte[] RegisterSessionHandle()
        {
            byte[] commandSpecificData = new byte[] { 0x01, 0x00, 0x00, 0x00, };
            return PackRequestHeader(0x65, 0, commandSpecificData);
        }

        /// <summary>
        /// 获取卸载一个已注册的会话的报文 ->
        /// Get a message to uninstall a registered session
        /// </summary>
        /// <returns>字节报文信息 -> BYTE message information </returns>
        public byte[] UnRegisterSessionHandle()
        {
            return PackRequestHeader(0x66, SessionHandle, new byte[0]);
        }

        /// <summary>
        /// A next step handshake agreement is required before disconnecting the Allenbradley plc
        /// </summary>
        /// <param name="socket">socket befor connection close </param>
        /// <returns>Whether the disconnect operation was successful</returns>
        protected BodaResult ExtraOnDisconnect()
        {
            // Unregister session Information
            var read = _commUnit.SendAndReceive(UnRegisterSessionHandle().ToList());
            if (!read.IsSuccess) return read;

            return BodaResult.CreateSuccessResult();
        }

        /// <summary>
        /// 生成读取直接节点数据信息的内容
        /// </summary>
        /// <param name="slot">PLC所在的槽号</param>
        /// <param name="cips">cip指令内容</param>
        /// <returns>最终的指令值</returns>
        public static byte[] PackCommandSpecificData(byte slot, params byte[][] cips)
        {
            System.IO.MemoryStream ms = new System.IO.MemoryStream();
            ms.WriteByte(0x00);
            ms.WriteByte(0x00);
            ms.WriteByte(0x00);
            ms.WriteByte(0x00);
            ms.WriteByte(0x01);     // 超时
            ms.WriteByte(0x00);
            ms.WriteByte(0x02);     // 项数
            ms.WriteByte(0x00);
            ms.WriteByte(0x00);     // 连接的地址项
            ms.WriteByte(0x00);
            ms.WriteByte(0x00);     // 长度
            ms.WriteByte(0x00);
            ms.WriteByte(0xB2);     // 连接的项数
            ms.WriteByte(0x00);
            ms.WriteByte(0x00);     // 后面数据包的长度，等全部生成后在赋值
            ms.WriteByte(0x00);

            ms.WriteByte(0x52);     // 服务
            ms.WriteByte(0x02);     // 请求路径大小
            ms.WriteByte(0x20);     // 请求路径
            ms.WriteByte(0x06);
            ms.WriteByte(0x24);
            ms.WriteByte(0x01);
            ms.WriteByte(0x0A);     // 超时时间
            ms.WriteByte(0xF0);
            ms.WriteByte(0x00);     // CIP指令长度
            ms.WriteByte(0x00);

            int count = 0;
            if (cips.Length == 1)
            {
                ms.Write(cips[0], 0, cips[0].Length);
                count += cips[0].Length;
            }
            else
            {
                ms.WriteByte(0x0A);   // 固定
                ms.WriteByte(0x02);
                ms.WriteByte(0x20);
                ms.WriteByte(0x02);
                ms.WriteByte(0x24);
                ms.WriteByte(0x01);
                count += 8;

                ms.Write(BitConverter.GetBytes((ushort)cips.Length), 0, 2);  // 写入项数
                ushort offect = (ushort)(0x02 + 2 * cips.Length);
                count += 2 * cips.Length;

                for (int i = 0; i < cips.Length; i++)
                {
                    ms.Write(BitConverter.GetBytes(offect), 0, 2);
                    offect = (ushort)(offect + cips[i].Length);
                }

                for (int i = 0; i < cips.Length; i++)
                {
                    ms.Write(cips[i], 0, cips[i].Length);
                    count += cips[i].Length;
                }
            }
            ms.WriteByte(0x01);     // Path Size
            ms.WriteByte(0x00);
            ms.WriteByte(0x01);     // port
            ms.WriteByte(slot);

            byte[] data = ms.ToArray();
            ms.Dispose();
            BitConverter.GetBytes((short)count).CopyTo(data, 24);
            data[14] = BitConverter.GetBytes((short)(data.Length - 16))[0];
            data[15] = BitConverter.GetBytes((short)(data.Length - 16))[1];
            return data;
        }


        private static byte[] BuildRequestPathCommand(string address)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                string[] tagNames = address.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);

                for (int i = 0; i < tagNames.Length; i++)
                {
                    string strIndex = string.Empty;
                    // 地址样式： ZROKStringNum[0]
                    int indexFirst = tagNames[i].IndexOf('[');
                    int indexSecond = tagNames[i].IndexOf(']');
                    if (indexFirst > 0 && indexSecond > 0 && indexSecond > indexFirst)
                    {
                        strIndex = tagNames[i].Substring(indexFirst + 1, indexSecond - indexFirst - 1);
                        tagNames[i] = tagNames[i].Substring(0, indexFirst);
                    }

                    ms.WriteByte(0x91);                        // 固定
                    ms.WriteByte((byte)tagNames[i].Length);    // 节点的长度值
                    byte[] nameBytes = Encoding.ASCII.GetBytes(tagNames[i]);
                    ms.Write(nameBytes, 0, nameBytes.Length);
                    // 如果不为偶数，则需要填充一个字节0x00
                    if (nameBytes.Length % 2 == 1) ms.WriteByte(0x00);

                    if (!string.IsNullOrEmpty(strIndex))
                    {
                        string[] indexs = strIndex.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                        for (int j = 0; j < indexs.Length; j++)
                        {
                            int index = Convert.ToInt32(indexs[j]);
                            if (index < 256)
                            {
                                ms.WriteByte(0x28);
                                ms.WriteByte((byte)index);
                            }
                            else
                            {
                                ms.WriteByte(0x29);
                                ms.WriteByte(0x00);
                                ms.WriteByte(BitConverter.GetBytes(index)[0]);
                                ms.WriteByte(BitConverter.GetBytes(index)[1]);
                            }
                        }
                    }
                }

                return ms.ToArray();
            }
        }

        /// <summary>
        /// 打包生成一个请求读取数据的节点信息，CIP指令信息
        /// </summary>
        /// <param name="address">地址</param>
        /// <param name="length">指代数组的长度</param>
        /// <returns>CIP的指令信息</returns>
        public static byte[] PackRequsetRead(string address, int length)
        {
            byte[] buffer = new byte[1024];
            int offect = 0;
            buffer[offect++] = CIP_READ_DATA;
            offect++;

            byte[] requestPath = BuildRequestPathCommand(address);
            requestPath.CopyTo(buffer, offect);
            offect += requestPath.Length;

            buffer[1] = (byte)((offect - 2) / 2);
            buffer[offect++] = BitConverter.GetBytes(length)[0];
            buffer[offect++] = BitConverter.GetBytes(length)[1];

            byte[] data = new byte[offect];
            Array.Copy(buffer, 0, data, 0, offect);
            return data;
        }

        /// <summary>
        /// 将CommandSpecificData的命令，打包成可发送的数据指令
        /// </summary>
        /// <param name="command">实际的命令暗号</param>
        /// <param name="session">当前会话的id</param>
        /// <param name="commandSpecificData">CommandSpecificData命令</param>
        /// <returns>最终可发送的数据命令</returns>
        public static byte[] PackRequestHeader(ushort command, uint session, byte[] commandSpecificData)
        {
            // header共24个字节, 默认全部是0x00
            byte[] buffer = new byte[commandSpecificData.Length + 24];
            // 命令2字节
            BitConverter.GetBytes(command).CopyTo(buffer, 0);
            // 用户数长度 2byte（总长度-Header的长度）
            BitConverter.GetBytes((ushort)commandSpecificData.Length).CopyTo(buffer, 2);
            // 会话句柄 4byte
            BitConverter.GetBytes(session).CopyTo(buffer, 4);

            // CommandSpecificData 指令指定数据 4byte
            Array.Copy(commandSpecificData, 0, buffer, 24, commandSpecificData.Length);
            return buffer;
        }

        /// <summary>
        /// Build a read command bytes
        /// </summary>
        /// <param name="address">the address of the tag name</param>
        /// <param name="length">Array information, if not arrays, is 1 </param>
        /// <returns>Message information that contains the result object </returns>
        public BodaResult<byte[]> BuildReadCommand(string[] address, int[] length)
        {
            if (address == null || length == null) return new BodaResult<byte[]>("address or length is null");
            if (address.Length != length.Length) return new BodaResult<byte[]>("address and length is not same array");

            try
            {
                List<byte[]> cips = new List<byte[]>();
                for (int i = 0; i < address.Length; i++)
                {
                    cips.Add(PackRequsetRead(address[i], length[i]));
                }
                byte[] commandSpecificData = PackCommandSpecificData(Slot, cips.ToArray());

                return BodaResult.CreateSuccessResult(PackRequestHeader(0x6F, SessionHandle, commandSpecificData));
            }
            catch (Exception ex)
            {
                return new BodaResult<byte[]>("Address Wrong:" + ex.Message);
            }
        }

        /// <summary>
        /// Build a read command bytes
        /// </summary>
        /// <param name="address">The address of the tag name </param>
        /// <returns>Message information that contains the result object </returns>
        public BodaResult<byte[]> BuildReadCommand(string[] address)
        {
            if (address == null) return new BodaResult<byte[]>("address or length is null");

            int[] length = new int[address.Length];
            for (int i = 0; i < address.Length; i++)
            {
                length[i] = 1;
            }

            return BuildReadCommand(address, length);
        }

        /// <summary>
        /// 批量读取数据信息，数据长度为读取的数组长度信息 -> Bulk read data information, data length for read array length information
        /// </summary>
        /// <param name="address">节点的名称 -> Name of the node </param>
        /// <param name="length">如果是数组，就为数组长度 -> In the case of arrays, the length of the array </param>
        /// <returns>带有结果对象的结果数据 -> Result data with result object </returns>
        public BodaResult<byte[]> Read(string[] address, int[] length)
        {
            BodaResult<byte[]> bodaResult = new BodaResult<byte[]>();
            // 指令生成 -> Instruction Generation
            BodaResult<byte[]> command = BuildReadCommand(address, length);
            if (!command.IsSuccess) return command;

            // 核心交互 -> Core Interactions
            var read = _commUnit.SendAndReceive(command.Content.ToList());
            if (!read.IsSuccess)
            {
                bodaResult.IsSuccess = false;
                bodaResult.Message = read.Message;
                return bodaResult;
            }

            // 检查反馈 -> Check Feedback
            BodaResult check = CheckResponse(read.Datas.ToArray());
            if (!check.IsSuccess) return BodaResult.CreateFailedResult<byte[]>(check);

            // 提取数据 -> Extracting data
            var dataRsp = ExtractActualData(read.Datas.ToArray(), true);
            bodaResult.Content = dataRsp.Datas.ToArray();
            return bodaResult;
        }

        /// <summary>
        /// Read data information, data length for read array length information
        /// </summary>
        /// <param name="address">Address format of the node</param>
        /// <param name="length">In the case of arrays, the length of the array </param>
        /// <returns>Result data with result object </returns>
        public BodaResult<byte[]> Read(string address, ushort length)
        {
            BodaResult<byte[]> bodaResult = new BodaResult<byte[]>();
            if (length > 1)
            {
                var res = ReadSegment(address, 0, length);
                if (res.IsSuccess)
                {
                    bodaResult.Content = res.Datas?.ToArray();
                }
                else
                {
                    bodaResult.IsSuccess = false;
                    bodaResult.Message = res.Message;
                }
            }
            else
            {
                bodaResult = Read(new string[] { address }, new int[] { length });
            }
            return bodaResult;
        }


        /// <summary>
        /// Read Segment Data Array form plc, use address tag name
        /// </summary>
        /// <param name="address">Tag name in plc</param>
        /// <param name="startIndex">array start index</param>
        /// <param name="length">array length</param>
        /// <returns>Results Bytes</returns>
        public BodaResult<byte> ReadSegment(string address, int startIndex, int length)
        {
            BodaResult<byte> bodaResult = new BodaResult<byte>();
            try
            {
                List<byte> bytesContent = new List<byte>();
                ushort alreadyFinished = 0;
                while (alreadyFinished < length)
                {
                    ushort readLength = (ushort)Math.Min(length - alreadyFinished, 100);
                    var read = ReadByCips(PackRequestReadSegment(address, startIndex + alreadyFinished, readLength));
                    if (!read.IsSuccess) return read;

                    bytesContent.AddRange(read.Datas);
                    alreadyFinished += readLength;
                }

                bodaResult.Datas = bytesContent;
                return bodaResult;
            }
            catch (Exception ex)
            {
                bodaResult.IsSuccess = false;
                bodaResult.Message = "Address Wrong:" + ex.Message;
                return bodaResult;
            }
        }

        /// <summary>
        /// 打包生成一个请求读取数据片段的节点信息，CIP指令信息
        /// </summary>
        /// <param name="address">节点的名称</param>
        /// <param name="startIndex">起始的索引位置</param>
        /// <param name="length">读取的数据长度，对于short来说，最大是489长度</param>
        /// <returns>CIP的指令信息</returns>
        public static byte[] PackRequestReadSegment(string address, int startIndex, int length)
        {
            byte[] buffer = new byte[1024];
            int offect = 0;
            buffer[offect++] = CIP_READ_FRAGMENT;
            offect++;


            byte[] requestPath = BuildRequestPathCommand(address + (address.EndsWith("]") ? string.Empty : $"[{startIndex}]"));
            requestPath.CopyTo(buffer, offect);
            offect += requestPath.Length;

            buffer[1] = (byte)((offect - 2) / 2);
            buffer[offect++] = BitConverter.GetBytes(length)[0];
            buffer[offect++] = BitConverter.GetBytes(length)[1];
            buffer[offect++] = BitConverter.GetBytes(0)[0];
            buffer[offect++] = BitConverter.GetBytes(0)[1];
            buffer[offect++] = BitConverter.GetBytes(0)[2];
            buffer[offect++] = BitConverter.GetBytes(0)[3];

            byte[] data = new byte[offect];
            Array.Copy(buffer, 0, data, 0, offect);
            return data;
        }

        private BodaResult<byte> ReadByCips(params byte[][] cips)
        {
            var read = ReadCipFromServer(cips);
            if (!read.IsSuccess) return read;

            // 提取数据 -> Extracting data
            return ExtractActualData(read.Datas.ToArray(), true);
        }

        /// <summary>
        /// 使用CIP报文和服务器进行核心的数据交换
        /// </summary>
        /// <param name="cips">Cip commands</param>
        /// <returns>Results Bytes</returns>
        public BodaResult<byte> ReadCipFromServer(params byte[][] cips)
        {
            byte[] commandSpecificData = PackCommandSpecificData(Slot, cips);
            byte[] command = PackRequestHeader(0x6F, SessionHandle, commandSpecificData);

            // 核心交互 -> Core Interactions
            var read = _commUnit.SendAndReceive(command.ToList());
            if (!read.IsSuccess) return read;

            // 检查反馈 -> Check Feedback
            BodaResult check = CheckResponse(read.Datas.ToArray());
            if (!check.IsSuccess) return BodaResult.CreateFailedResult<byte>(check);

            return read;
        }

        /// <summary>
        /// 从PLC反馈的数据解析
        /// </summary>
        /// <param name="response">PLC的反馈数据</param>
        /// <param name="isRead">是否是返回的操作</param>
        /// <returns>带有结果标识的最终数据</returns>
        public static BodaResult<byte> ExtractActualData(byte[] response, bool isRead)
        {
            BodaResult<byte> bodaResult = new BodaResult<byte>();
            List<byte> data = new List<byte>();

            int offect = 38;
            ushort count = BitConverter.ToUInt16(response, 38);    // 剩余总字节长度，在剩余的字节里，有可能是一项数据，也有可能是多项
            if (BitConverter.ToInt32(response, 40) == 0x8A)
            {
                // 多项数据
                offect = 44;
                int dataCount = BitConverter.ToUInt16(response, offect);
                for (int i = 0; i < dataCount; i++)
                {
                    int offectStart = BitConverter.ToUInt16(response, offect + 2 + i * 2) + offect;
                    int offectEnd = (i == dataCount - 1) ? response.Length : (BitConverter.ToUInt16(response, (offect + 4 + i * 2)) + offect);
                    ushort err = BitConverter.ToUInt16(response, offectStart + 2);
                    switch (err)
                    {
                        case 0x04: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley04 };
                        case 0x05: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley05 };
                        case 0x06:
                            {
                                // 06的错误码通常是数据长度太多了
                                // CC是符号返回，D2是符号片段返回
                                if (response[offect + 2] == 0xD2 || response[offect + 2] == 0xCC)
                                    return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley06 };
                                break;
                            }
                        case 0x0A: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley0A };
                        case 0x13: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley13 };
                        case 0x1C: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley1C };
                        case 0x1E: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley1E };
                        case 0x26: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley26 };
                        case 0x00: break;
                        default: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.UnknownError };
                    }

                    if (isRead)
                    {
                        for (int j = offectStart + 6; j < offectEnd; j++)
                        {
                            data.Add(response[j]);
                        }
                    }
                }
            }
            else
            {
                // 单项数据
                byte err = response[offect + 4];
                switch (err)
                {
                    case 0x04: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley04 };
                    case 0x05: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley05 };
                    case 0x06:
                        {
                            if (response[offect + 2] == 0xD2 || response[offect + 2] == 0xCC)
                                return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley06 };
                            break;
                        }
                    case 0x0A: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley0A };
                    case 0x13: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley13 };
                    case 0x1C: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley1C };
                    case 0x1E: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley1E };
                    case 0x26: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.AllenBradley26 };
                    case 0x00: break;
                    default: return new BodaResult<byte>() { IsSuccess = false, ErrorCode = err, Message = StringResources.Language.UnknownError };
                }

                if (isRead)
                {
                    for (int i = offect + 8; i < offect + 2 + count; i++)
                    {
                        data.Add(response[i]);
                    }
                }
            }

            bodaResult.IsSuccess = true;
            bodaResult.Datas.AddRange(data.ToArray());
            return bodaResult;
        }

    }
}
